/**
 * Project : PasswordLockerUI
 * Package : org.ozzy.pwdlocker.ui.helper
 * File    : $.java
 */
package com.yncmcc.Util;

import com.yncmcc.Entity.UserEntity;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.CharSetUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <code>$</code>
 * description.<p>
 * <p>
 * <blockquote><pre>
 * use for ...
 * </pre></blockquote>
 *
 * @author Zhou Yin (<a href="mailto:vambad@gmail.com">Contact Me</a>)
 * @version 1.0, 2015年2月12日
 * @since 1.0
 */
public class U {

    private static Logger log = LoggerFactory.getLogger(U.class);

    private static final String NUMERIC_CHARS = "0123456789";
    private static final String UPPER_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String LOWER_CHARS = "abcdefghijklmnopqrstuvwxyz";
    private static final String MARK_CHARS = "~!@#$%^&*()-_+.";

    public static final String ALL_IN_ONE = "[0-9a-zA-Z\\~\\`\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\=\\_\\+\\,\\.]+";
    private static final String NUM_REG = "[0-9]+";
    private static final String UPPER_REG = "[A-Z]+";
    private static final String LOWER_REG = "[a-z]+";
    private static final String MARK_REG = "[\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\_\\+\\.]+";

    public static final String EMPTY = "";

    public static final String HASH_ALGORITHM = "SHA-1";
    public static final int HASH_INTERATIONS = 1024;
    private static final int SALT_SIZE = 8;
    private static SecureRandom RANDOM = new SecureRandom();

    public static FastDateFormat YYYYMMDD = FastDateFormat.getInstance("yyyyMMdd");
    public static FastDateFormat YYYYMMDDHHMMSS = FastDateFormat.getInstance("yyyyMMddHHmmss");
    public static FastDateFormat YYYY_MM = FastDateFormat.getInstance("yyyy-MM");
    public static FastDateFormat YYYY_MM_DD = FastDateFormat.getInstance("yyyy-MM-dd");
    public static FastDateFormat YYYY_MM_DD_HH_MM = FastDateFormat.getInstance("yyyy-MM-dd HH:mm");
    public static FastDateFormat YYYY_MM_DD_HH_MM_SS = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
    public static final BigDecimal SCALA = new BigDecimal("100");
    public static final BigDecimal HALF_UP = new BigDecimal("0.5");
    public static final DecimalFormat CODE_000000 = new DecimalFormat("000000");

    public static final String SESSION_CAPTCHA = "jcaptcha";

    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    public static String trim(String str) {
        return str == null ? null : str.trim();
    }

    public static String trimToNull(String str) {
        String ts = trim(str);
        return isEmpty(ts) ? null : ts;
    }

    public static String trimToEmpty(String str) {
        return str == null ? EMPTY : str.trim();
    }

    public static String genRandomString(int length, boolean hasDigital, boolean hasMark, boolean hasUpper, boolean hasLower) {
        if (length <= 0) {
            return EMPTY;
        }
        StringBuffer sb = new StringBuffer();
        if (hasDigital) {
            sb.append(NUMERIC_CHARS);
        }
        if (hasMark) {
            sb.append(MARK_CHARS);
        }
        if (hasUpper) {
            sb.append(UPPER_CHARS);
        }
        if (hasLower) {
            sb.append(LOWER_CHARS);
        }
        char[] possiblesChars = sb.toString().toCharArray();
        Random random = new SecureRandom();

        StringBuffer sb2 = new StringBuffer(length);
        for (int i = 0; i < length; i++) {
            sb2.append(possiblesChars[random.nextInt(possiblesChars.length)]);
        }
        return sb2.toString();
    }

    public static int passwordScore(String password) {
        if (trimToNull(password) == null) {
            return 0;
        }

        int score = 0;
        Matcher nummatcher = Pattern.compile(NUM_REG).matcher(password);
        while (nummatcher.find()) {
            score += 5;
        }
        Matcher upmatcher = Pattern.compile(UPPER_REG).matcher(password);
        while (upmatcher.find()) {
            score += 10;
        }
        Matcher lowmatcher = Pattern.compile(LOWER_REG).matcher(password);
        while (lowmatcher.find()) {
            score += 10;
        }
        Matcher markmatcher = Pattern.compile(MARK_REG).matcher(password);
        while (markmatcher.find()) {
            score += 15;
        }

        int result = score + (password.length() * 5);
        return result >= 100 ? 100 : result;
    }

    public static Date fromStringToDate(String text) {
        if (isEmpty(text)) {
            return null;
        }
        try {
            Date date = DateUtils.parseDateStrictly(text, "yyyy-MM-dd", "yyyy-MM-dd HH:mm", "HH:mm");
            return date;
        } catch (ParseException e) {
            return null;
        }
    }

    public static byte[] generateSalt(int numBytes) {
        Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", numBytes);

        byte[] bytes = new byte[numBytes];
        RANDOM.nextBytes(bytes);
        return bytes;
    }

    public static String encodeHex(byte[] input) {
        return Hex.encodeHexString(input);
    }

    public static byte[] decodeHex(String input) {
        try {
            return Hex.decodeHex(input.toCharArray());
        } catch (DecoderException e) {
            throw U.unchecked(e);
        }
    }

    public static byte[] sha1(byte[] input, byte[] salt, int iterations) {
        return digest(input, HASH_ALGORITHM, salt, iterations);
    }

    private static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);

            if (salt != null) {
                digest.update(salt);
            }

            byte[] result = digest.digest(input);

            for (int i = 1; i < iterations; i++) {
                digest.reset();
                result = digest.digest(result);
            }
            return result;
        } catch (Exception e) {
            throw U.unchecked(e);
        }
    }

    public static RuntimeException unchecked(Throwable ex) {
        if (ex instanceof RuntimeException) {
            return (RuntimeException) ex;
        } else {
            return new RuntimeException(ex);
        }
    }

    public static void entryptPassword(UserEntity user) {
        byte[] salt = U.generateSalt(SALT_SIZE);
        user.setUserPrimarySalt(U.encodeHex(salt));

        byte[] hashPassword = U.sha1(user.getUserPass().getBytes(), salt, HASH_INTERATIONS);
        user.setUserPass(U.encodeHex(hashPassword));
    }

    public static class Money {

        private Long amount = 0L; // 精度是分（小数点后2位） amount * 100

        public Money() {
        }

        public Money(Long amount) {
            this.amount = amount == null ? 0L : amount;
        }

        public Money(String string) {
            string = StringUtils.trimToNull(string);
            if (string == null) {
                return;
            } else {
                if (string.indexOf(',') != -1) {
                    string = CharSetUtils.delete(string, ",");
                }
                if (!NumberUtils.isNumber(string)) {
                    return;
                } else {
                    BigDecimal amountDecimal = new BigDecimal(string);
                    this.amount = amountDecimal.multiply(SCALA).add(HALF_UP.multiply(new BigDecimal(amountDecimal.signum()))).longValue();
                }
            }
        }

        public Long getAmount() {
            return amount;
        }

        public void setAmount(Long amount) {
            this.amount = amount;
        }

        public String toDetailString() {
            StringBuilder builder = new StringBuilder();
            builder.append("Money [\n\tamount=");
            builder.append(amount);
            builder.append("\n]");
            return builder.toString();
        }

        @Override
        public String toString() {
            return new BigDecimal(this.amount).divide(SCALA).setScale(2, RoundingMode.HALF_UP).toPlainString();
        }
    }

    public static String utf8ToGb2312(String str) {
        try {
            String utf8 = new String(str.getBytes("UTF-8"));
            String unicode = new String(utf8.getBytes(), "UTF-8");
            return new String(unicode.getBytes("GB2312"));
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
            return str;
        }
    }

    private static final String Algorithm = "DESede"; //定义加密算法,可用 DES,DESede,Blowfish

    //keybyte为加密密钥，长度为24字节
    //src为被加密的数据缓冲区（源）
    public static byte[] encryptMode(byte[] keybyte, byte[] src) {
        try {
            //生成密钥
            SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
            //加密
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            return c1.doFinal(src);//在单一方面的加密或解密
        } catch (java.security.NoSuchAlgorithmException e1) {
            // TODO: handle exception
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    //keybyte为加密密钥，长度为24字节
    //src为加密后的缓冲区
    public static byte[] decryptMode(byte[] keybyte, byte[] src) {
        try {
            //生成密钥
            SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
            //解密
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.DECRYPT_MODE, deskey);
            return c1.doFinal(src);
        } catch (java.security.NoSuchAlgorithmException e1) {
            // TODO: handle exception
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    public static String getRealIP(HttpServletRequest request) {
        String remoteIp = "";
        remoteIp = request.getHeader("x-forwarded-for");
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getHeader("X-Real-IP");
        }
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getHeader("Proxy-Client-IP");
        }
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getHeader("WL-Proxy-Client-IP");
        }
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getHeader("HTTP_CLIENT_IP");
        }
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getRemoteAddr();
        }
        if (remoteIp == null || remoteIp.isEmpty() || "unknown".equalsIgnoreCase(remoteIp)) {
            remoteIp = request.getRemoteHost();
        }
        return remoteIp;
    }

    public static void main(String[] args) throws Exception {
        //	String signKey = "H4c3tqQ0BC20151020115821";
    /*	CryptUtilImpl cryptUtil = new CryptUtilImpl();
		String encryptSignKey = cryptUtil.cryptDes(signKey, signKey);
		System.out.println(encryptSignKey);*/

        //添加新安全算法,如果用JCE就要把它添加进去
	/*	Security.addProvider( new com.sun.crypto.provider.SunJCE() );
		String password = signKey;//密码
		System.out.println( "加密前的字符串:" + password );
		byte[] encoded = encryptMode( password.getBytes(), password.getBytes() );
		String pword = Base64.encode( encoded );
		System.out.println( "加密后的字符串:" + pword );

		byte[] reqPassword = Base64.decode( pword );
		byte[] srcBytes = decryptMode( password.getBytes(), reqPassword );
		System.out.println( "解密后的字符串:" + ( new String( srcBytes ) ) );*/

	/*	User user = new User();
		user.setPassword( "123456" );
		entryptPassword( user );
		System.out.println( user.getPassword() + "@" + user.getHashsalt() );*/

        //	U.parseWeather( "D:\\Users\\Administrator\\Downloads\\2016年5月5日发布三天预报.txt" );
        String html = StringEscapeUtils.escapeHtml4("images/v3view@2x.png");
        String ecma = StringEscapeUtils.escapeEcmaScript("images/v3view@2x.png");
        System.out.println(html + " # " + ecma);

        Map<String, Integer> stat = new HashMap<String, Integer>();
        stat.put("感谢参与1%", 0);
        stat.put("0.5元30%", 0);
        stat.put("1元30%", 0);
        stat.put("1.5元15%", 0);
        stat.put("2元24%", 0);
        for (int i = 0; i < 1000000; i++) {
            // double rng = RANDOM.nextDouble();
            int num = RANDOM.nextInt(100);// (int) ( rng * 100 );
            if (num == 0) {
                stat.put("感谢参与1%", stat.get("感谢参与1%") + 1);
            }
            if (num > 0 && num <= 30) {
                stat.put("0.5元30%", stat.get("0.5元30%") + 1);
            }
            if (num > 30 && num <= 60) {
                stat.put("1元30%", stat.get("1元30%") + 1);
            }
            if (num > 60 && num <= 75) {
                stat.put("1.5元15%", stat.get("1.5元15%") + 1);
            }
            if (num > 75 && num <= 99) {
                stat.put("2元24%", stat.get("2元24%") + 1);
            }
        }
        System.out.println(stat);
    }

}
